package com.ZeroCarbon.service.impl;

import cn.hutool.core.lang.UUID;
import com.ZeroCarbon.common_service.CommonService;
import com.ZeroCarbon.domain.dto.ReplyDTO;
import com.ZeroCarbon.domain.po.Comment;
import com.ZeroCarbon.domain.po.Reply;
import com.ZeroCarbon.domain.po.UserReply;
import com.ZeroCarbon.exception.BusinessLogicException;
import com.ZeroCarbon.mapper.ReplyMapper;
import com.ZeroCarbon.service.IReplyService;
import com.ZeroCarbon.service.IUserReplyService;
import com.ZeroCarbon.utils.BusinessMethodUtils;
import com.ZeroCarbon.utils.UserHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ZeroCarbon.BusinessUtils.UserClientUtils.*;
import static com.ZeroCarbon.exception.BusinessLogicException.BUSY_EXCEPTION;
import static com.ZeroCarbon.exception.BusinessLogicException.ERROR_EXCEPTION;
import static com.ZeroCarbon.method.RemoteClientCall.OperationType.GET_AVATAR;
import static com.ZeroCarbon.method.RemoteClientCall.OperationType.GET_USERNAME;
import static com.ZeroCarbon.prefix.MySqlKey.REPLY_PREFIX;
import static com.ZeroCarbon.prefix.RedisKey.THUMB_REPLY;

@Service
@RequiredArgsConstructor
public class ReplyServiceImpl extends ServiceImpl<ReplyMapper, Reply> implements IReplyService {

    private final IUserReplyService userReplyService;

    private final StringRedisTemplate redis;

    private CommonService<Reply> serviceUtils;

    @Autowired
    public void initServiceUtils(ReplyMapper replyMapper) {
        serviceUtils = new CommonService<>(replyMapper);
    }

    /**
     * 回复评论
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replyComment(Reply reply) throws BusinessLogicException {
        //用户id
        String userId = UserHolder.getUser();
        //回复key
        String id = REPLY_PREFIX + UUID.randomUUID();
        //设置回复信息
        reply.setId(id)
                .setLiked(0)
                .setDay(LocalDateTime.now());
        //用户回复对象
        UserReply userReply;
        try {
            //保存回复
            if (!save(reply)) {
                throw new BusinessLogicException(ERROR_EXCEPTION);
            }
            //创建用户回复类对象
            userReply = new UserReply(id, userId);
            //获取回复相关评论
            Comment comment = Db.lambdaQuery(Comment.class)
                    .eq(Comment::getId, reply.getReplyId())
                    .one();
            //不存在的情况
            if (comment == null) {
                throw new BusinessLogicException("评论不存在");
            }
            //回复评论数+1
            boolean updateReplyNum = Db.lambdaUpdate(Comment.class)
                    .eq(Comment::getId, reply.getReplyId())
                    .set(Comment::getChildNum, comment.getChildNum() + 1)
                    .update();
            //更新失败
            if (!updateReplyNum) {
                throw new BusinessLogicException("回复评论失败");
            }
        } catch (BusinessLogicException e) {
            throw new BusinessLogicException(e.getMessage());
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //保存用户回复对象
        if (!userReplyService.save(userReply)) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }

    /**
     * 获取回复
     *
     * @param id 回复评论id
     */
    @Override
    public List<ReplyDTO> getSubComments(String id) throws BusinessLogicException {
        //回复构造器
        LambdaQueryWrapper<Reply> replyWrapper = new LambdaQueryWrapper<Reply>()
                .eq(Reply::getReplyId, id);
        //回复集合
        List<Reply> replies;
        try {
            //获取所有回复
            replies = list(replyWrapper);
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
        //如果为空则返回空集合
        if (replies.isEmpty()) {
            return Collections.emptyList();
        }
        //对集合加以处理
        return replies.stream()
                .map(reply -> {
                    //转化对象
                    ReplyDTO replyDTO = reply.toReplyDTO();
                    //查找回复对应用户id
                    UserReply userReply = Db.lambdaQuery(UserReply.class)
                            .eq(UserReply::getId, replyDTO.getId())
                            .one();
                    //获取用户id
                    String userId = userReply.getUserId();
                    //记录用户信息
                    Map<String, String> userClientInformation;
                    try {
                        //获取用户对应的用户名和头像
                        userClientInformation = getUserClientInformation(userId,
                                GET_USERNAME,
                                GET_AVATAR);
                    } catch (Exception e) {
                        throw new RuntimeException(BUSY_EXCEPTION);
                    }
                    //设置额外信息进行返回
                    return replyDTO.setAvatar(userClientInformation.get(AVATAR))
                            .setUsername(userClientInformation.get(USERNAME))
                            .setUserId(userId);
                }).collect(Collectors.toList());
    }

    /**
     * 给评论点赞
     */
    @Override
    public int thumbsUpReply(String id) throws BusinessLogicException {
        //获取用户id
        String userId = UserHolder.getUser();
        //获取点赞key
        String key = THUMB_REPLY + id;
        //获取回复构造器
        LambdaQueryWrapper<Reply> likedWrapper = new LambdaQueryWrapper<Reply>()
                .select(Reply::getLiked).eq(Reply::getId, id);
        //已点赞再次点击则取消赞
        int step = BusinessMethodUtils.isExist(key, userId) ? -1 : 1;
        //更新点赞
        Boolean isSuccess = serviceUtils.updateSqlIncrementOrCheck("liked", step, id);
        //修改redis中的记录
        if (step > 0 && isSuccess) {
            redis.opsForSet().remove(key, userId);
        } else {
            redis.opsForSet().add(key, userId);
        }
        try {
            //返回点赞数
            return getOne(likedWrapper).getLiked();
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }

    /**
     * 判断当前用户是否喜欢该评论
     */
    @Override
    public Boolean isUserLikeReply(String id) {
        //获取用户id
        String userId = UserHolder.getUser();
        //获取点赞回复key
        String key = THUMB_REPLY + id;
        //返回判断结果
        return BusinessMethodUtils.isExist(key, userId);
    }

    /**
     * 删除回复
     */
    @Override
    public void deleteReply(String id) throws BusinessLogicException {
        //删除redis相关回复键
        String key = THUMB_REPLY + id;
        try {
            //从redis删除
            redis.delete(key);
            //从数据库删除
            if (!removeById(id)) {
                throw new BusinessLogicException();
            }
        } catch (Exception e) {
            throw new BusinessLogicException(ERROR_EXCEPTION);
        }
    }
}
